/*
 * Dcm_UDS0x38.c
 *
 *  Created on: 2018-8-22
 *      Author: tao.yu
 */

#include "UDS.h"


/****************************************************************
     UDS: RequestFileTransfer (38 hex) service
 ***************************************************************/
#if (STD_ON == DCM_UDS_SERVICE0X38_ENABLED)
/***************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_Uds0x38ServiceConditionCheck(
        uint8 ProtocolCtrlId,
        uint8 MsgCtrlId)
{
    Std_ReturnType ret = E_OK;

    /*************************************************/
#if(STD_ON == DCM_SESSION_FUNC_ENABLED)
    /*session check,check whether the current
     * session supports the request service*/
    ret = DsdInternal_SesCheck(ProtocolCtrlId,
            SID_REQUEST_FILE_TRANSFER);
    if(E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-073[DCM211]****/
        /*the current session does not support
         *  the request service,send NRC = 0x7F*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
#endif

    /*************************************************/
#if(STD_ON == DCM_SECURITY_FUNC_ENABLED)
    /*security check,check whether the current
     * security supports the request service*/
    ret = DsdInternal_SecurityCheck(ProtocolCtrlId,
            SID_REQUEST_FILE_TRANSFER);
    if(E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-074[DCM217]****/
        /*the current security does not support
         *  the request service,send NRC = 0x33*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SECURITYACCESSDENIED);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
#endif
    /*min-length check*/
    if (DCM_UDS0X38_REQ_DATA_MINLENGTH
            > Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen)
    {
        /*the min length of message is not correct,send NRC 0x13*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"


/*******************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
FUNC(Std_ReturnType, DCM_CODE)Dcm_UDS0x38(
        Dcm_OpStatusType OpStatus,
        uint8  ProtocolCtrlId,
        P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_VAR) ErrorCode)
{
    uint8  MsgCtrlId = 0u;
    Std_ReturnType ret = E_OK;
    uint8  TxChannelCtrlIndex = 0u;
    uint8  TxChannelCfgIndex = 0u;
    uint16 Offset = 0u;
    uint16 filePathAndNameLength = 0;
    uint16 fileSizeParameterLength = 0;
    uint8 index = 0u;
    uint8 modeOfOperation;
    uint8* filePathAndName = NULL_PTR;
    uint8 dataFormatIdentifier = 0;
    uint16 ReqOffset = 0u;
    uint16 ResOffset = 0u;
    uint8* fileSizeUncompressedOrDirInfoLength = NULL_PTR;
    uint8* fileSizeCompressed = NULL_PTR;
    uint32 BlockLength = 0;
    uint8 lengthFormatIdentifier;

    /*************************************************/
    /*if the required protocol is configured,get the index of runtime datum*/
    MsgCtrlId =  Dcm_ProtocolCtrl[ProtocolCtrlId].MsgCtrlIndex;

    /*************************************************/
    ret = Dcm_Uds0x38ServiceConditionCheck(ProtocolCtrlId, MsgCtrlId);
    if(E_OK != ret)
    {
     return ret;
    }

    modeOfOperation = Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[1];
    if ((modeOfOperation < 0x01u) || (modeOfOperation > 0x05u))
    {
        /*the modeOfOperation is not correct,send NRC 0x31*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId, DCM_E_REQUESTOUTOFRANGE);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    filePathAndNameLength = (uint16)((uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[2u]
                          | (uint16)((uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[3u] << 8u));
    filePathAndName = &(Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[4u]);
    ReqOffset = 4u + filePathAndNameLength;
    if ((modeOfOperation != 0x02u) && (modeOfOperation != 0x05u))
    {
        dataFormatIdentifier = Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[ReqOffset];
        ReqOffset += 1u;
        if (modeOfOperation != 0x04u)
        {
            if (Dcm_DspCfg.DcmDspRequestFileTransfer != NULL_PTR)
            {
                fileSizeParameterLength =
                      (uint16)Dcm_DspCfg.DcmDspRequestFileTransfer->
                      DcmRequestFileTransferFileSizeParameterLength;
            }
            else
            {
                fileSizeParameterLength
                = (uint16)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[ReqOffset];
            }
            ReqOffset += 1u;
            fileSizeUncompressedOrDirInfoLength =
                    &(Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[ReqOffset]);
            ReqOffset += fileSizeParameterLength;
            fileSizeCompressed =
                    &(Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[ReqOffset]);
            ReqOffset += fileSizeParameterLength;
        }
    }

    /*[SWS_Dcm_01086][SWS_Dcm_01089]*/
    if (ReqOffset < Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen)
    {
        /*the length of message is not correct,send NRC 0x13*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    TxChannelCtrlIndex = Dcm_MsgCtrl[MsgCtrlId].Dcm_TxCtrlChannelIndex;
    TxChannelCfgIndex  = Dcm_ChannelCtrl[TxChannelCtrlIndex].Dcm_ChannelCfgIndex;
    Offset = (Dcm_DslCfg.pDcmChannelCfg)[TxChannelCfgIndex].offset;

    /*[SWS_Dcm_01084][SWS_Dcm_01085][SWS_Dcm_01089]*/
    ret = Dcm_ProcessRequestFileTransfer(OpStatus,
                                            modeOfOperation,
                                            fileSizeParameterLength,
                                            filePathAndName,
                                            dataFormatIdentifier,
                                            fileSizeUncompressedOrDirInfoLength,
                                            fileSizeCompressed,
                                            &BlockLength,
                                            ErrorCode);
    if (E_NOT_OK == ret)
    {/*[SWS_Dcm_01088] */
        /*the processing is not successful,send NRC */
        (void)DsdInternal_SetNrc(ProtocolCtrlId, *ErrorCode);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    else if (DCM_E_PENDING == ret)
    {
        Dcm_MsgCtrl[MsgCtrlId].Dcm_OpStatus = DCM_PENDING;
        return ret;
    }
    else
    {
        /*idle*/
    }

    /**********************************************************
     * assemble positive response
     *********************************************************/
    /*the processing is successful,assemble positive response*/
    SchM_Enter_Dcm(Dcm_Channel);
    Dcm_Channel[Offset] = 0x78;             /*response SID*/
    Dcm_Channel[Offset + 1u] = modeOfOperation;    /*modeOfOperation*/
    ResOffset = Offset + 2u;
    if (modeOfOperation != 0x02u)
    {
        if (Dcm_DspCfg.DcmDspRequestFileTransfer != NULL_PTR)
        {
            lengthFormatIdentifier = Dcm_DspCfg.DcmDspRequestFileTransfer->
                    DcmRequestFileTransferLengthFormatIdentifier;
        }
        else
        {
            lengthFormatIdentifier = 4u;
        }
        Dcm_Channel[ResOffset] = lengthFormatIdentifier;
        ResOffset += 1u;

        for (index = 0; index < lengthFormatIdentifier; index++)
        {
            Dcm_Channel[ResOffset] = (uint8)(BlockLength
                    >> (uint8)((lengthFormatIdentifier - index - 1u) * 8u));
            /*maxNumberOfBlockLength*/
            ResOffset += 1u;
        }

        if (modeOfOperation == 0x05u)
        {
            Dcm_Channel[ResOffset] = 0x00u;
        }
        else
        {
            Dcm_Channel[ResOffset] = dataFormatIdentifier;
        }
        ResOffset += 1u;

        if ((modeOfOperation != 0x01u) && (modeOfOperation != 0x03u))
        {
            Dcm_Channel[ResOffset] = (uint8)fileSizeParameterLength;
            ResOffset += 1u;

            for (index = 0; index < fileSizeParameterLength; index++)
            {
                Dcm_Channel[ResOffset] = *fileSizeUncompressedOrDirInfoLength;
                fileSizeUncompressedOrDirInfoLength++;
                ResOffset += 1u;
            }

            if (modeOfOperation != 0x05u)
            {
                for (index = 0; index < fileSizeParameterLength; index++)
                {
                    Dcm_Channel[ResOffset] = *fileSizeCompressed;
                    fileSizeCompressed++;
                    ResOffset += 1u;
                }
            }
        }
    }
    SchM_Exit_Dcm(Dcm_Channel);

    /* check tx data length */
    if ((ResOffset - Offset)
            > (Dcm_DslCfg.pDcmChannelCfg[TxChannelCfgIndex].Dcm_DslBufferSize))
    {
        /*Pdu length is bigger than buffer size */
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_RESPONSETOOLONG);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }


    /* get address */
    Dcm_DspProgram.address = 0UL;
    /* set index to 0, for service 0x36 */
    Dcm_DspProgram.blockId = 0x00;
    /* set 0x36 service status to DCM_UDS0X36_TO_UPLOAD*/
    switch(modeOfOperation)
    {
    case 0x01u:
        Dcm_DspProgram.Status = DCM_UDS0X38_0x01;
        break;
    case 0x02u:
        Dcm_DspProgram.Status = DCM_UDS0X38_0x02;
        break;
    case 0x03u:
        Dcm_DspProgram.Status = DCM_UDS0X38_0x03;
        break;
    case 0x04u:
        Dcm_DspProgram.Status = DCM_UDS0X38_0x04;
        break;
    case 0x05u:
        Dcm_DspProgram.Status = DCM_UDS0X38_0x05;
        break;
    default:
        break;
    }
    /*memory the MemoryIdInfoIndex*/
    Dcm_DspProgram.MemoryIdInfoIndex = 0xFF;
    /*memory one block size*/
    Dcm_DspProgram.BlockLength = BlockLength;

    SchM_Enter_Dcm(Dcm_MsgCtrl);
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResMaxDataLen = (Dcm_MsgLenType)ResOffset - Offset;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResDataLen    = (Dcm_MsgLenType)ResOffset - Offset;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.pResData      = &Dcm_Channel[Offset];
    SchM_Exit_Dcm(Dcm_MsgCtrl);
    DsdInternal_ProcessingDone(ProtocolCtrlId);

    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

#endif
